/**
 * Copyright 2011 Sibaozuan(superskysbz@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package summary.android.async;

import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.util.HashMap;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;

/**
 *图片异步加载器，具有图片异步下载和图片缓存的功能
 * 
 * @author Sibaozuan(superskysbz@gmail.com)
 * 
 */
public class AsyncImageLoader {
	/**
	 * 图片缓存器，采用SoftReference缓存方式缓存
	 */
	private HashMap<String, SoftReference<Drawable>> imageCache;

	public AsyncImageLoader() {
		imageCache = new HashMap<String, SoftReference<Drawable>>();
	}

	/**
	 * 此方法首先从图片缓存中查找图片，如果找到了，就返回此图片，如果没有找到，将返回空
	 * 此时将会开启一个新线程从imageUrl处下载图片，由于图片下载完时，此方法的调用已完成
	 * 因此不能将下载的图片作为返回值返回，所以需要用Handler来更新界面，而Handler在更新界面时是
	 * 调用了ImageCallback接口的imageLoaded方法来更新界面的，因此调用此方法的地方必须实现此 接口，并作为参数传给此方法
	 * 
	 * @param imageUrl
	 *              图片下载地址
	 * @param imageCallback
	 *              回调接口，当图片刚从远程下载完而要更新界面时，需要调用此接口才能更新界面
	 * @return 返回从图片缓存中找到的图片，如果没有找到，则返回空
	 */
	public Drawable loadDrawable(final String imageUrl, final ImageCallback imageCallback) {
		if (imageCache.containsKey(imageUrl)) {
			SoftReference<Drawable> softReference = imageCache.get(imageUrl);
			Drawable drawable = softReference.get();
			if (drawable != null) {
				return drawable;
			}
		}
		if (!TextUtils.isEmpty(imageUrl)) {
			// 若缓存中没有想要的图片，需从远程下载，此时需要用Handler对象来更新界面
			final Handler handler = new Handler() {
				@Override
				public void handleMessage(Message message) {
					// 更新界面只需调用ImageCallback接口的imageLoaded方法就行了
					// 因此实现此方法很重要
					imageCallback.imageUpdated((Drawable) message.obj, imageUrl);
				}
			};
			// 开启一个线程，用于下载图片，每张图片的下载都由一个单独的线程来完成
			// 图片下载完后，要先放入缓存，在更新界面
			 new Thread() {
				@Override
				public void run() {
					// 从imageUrl处下载图片
					Drawable drawable = loadImageFromUrl(imageUrl);
					// 将下载的图片放入缓存
					imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
					// 将下载的图片发送给handler，好更新界面
					Message message = handler.obtainMessage(0, drawable);
					handler.sendMessage(message);
				}
			}.start();
		}
		return null;
	}

	/**
	 * @param imageUrl
	 *              下载图片的地址
	 * @return 返回从imageUrl处下载的图片
	 */
	private Drawable loadImageFromUrl(String imageUrl) {
		HttpClient hClient = new DefaultHttpClient();
		HttpGet get = new HttpGet(imageUrl);
		try {
			HttpResponse response = hClient.execute(get);
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				InputStream inputStream = response.getEntity().getContent();
				return Drawable.createFromStream(inputStream, null);
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 
	 * @author Sibaozuan(superskysbz@gmail.com)
	 * 图片刚从远程下载完后，需要在图片加载端实现此接口才能更新界面 利用此接口，图片下载完后，就能自动更新界面
	 */
	public interface ImageCallback {
		/**
		 * @param imageDrawable
		 *              刚从远程下载的图片，实现此接口的地方就是用它更新界面的
		 * @param imageUrl
		 *              图片的下载地址
		 */
		public void imageUpdated(Drawable imageDrawable, String imageUrl);
	}
}
